// $Id: loggercountbandwidthutilization.cpp 63 2004-10-22 14:33:20Z jonas $
#include "loggercountbandwidthutilization.h"
#include "loghandler.h"
#include "clock.h"
#include "partitionizer.h"
#include "transfer.h"

#include <iostream>

/**
 * Init members and register apropriate listeners at the log handler.
 */
LoggerCountBandwidthUtilization::LoggerCountBandwidthUtilization()
	: m_eos(0)
{
	LogHandler::getInstance()->addLogger(this, "network_transfer");
	LogHandler::getInstance()->addLogger(this, "clock_tick");
}

/**
 * @todo Describe this...
 */
/*LoggerCountBandwidthUtilization::~LoggerCountBandwidthUtilization()
{
}*/

/**
 * Creates output file and writes headers to it. Prepares for the simulation.
 */
void LoggerCountBandwidthUtilization::eos_simulate_start(void *eos)
{
	openFile(&m_fout, "countbandwidthutilization.csv");
	m_eos = (Eos *) eos;

	// Reset bandwidths
	resetBandwidths();

	// Print descriptive text to logfile
	m_fout << "Time Step";

	// Find out about number of partitions and create a transfer list for each of them
	for (int i=0; i<Partitionizer::getInstance()->getPartitionCount(); i++) {
		///m_nodePartitionSpeeds.push_back(new map<Node *, NodeSpeedHelper *>());
		m_fout << ", " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down Average, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down Minimum, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down First Quartile, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down Median, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down Third Quartile, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down Maximum, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Down Partition member count, " <<

		Partitionizer::getInstance()->getPartitionName(i) << "-Up Average, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Up Minimum, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Up First Quartile, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Up Median, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Up Third Quartile, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Up Maximum, " <<
		Partitionizer::getInstance()->getPartitionName(i) << "-Up Partition member count";
	}
	m_fout << endl;
}

/**
 * Closes the file.
 */
void LoggerCountBandwidthUtilization::eos_simulate_stop(void *)
{
	// Close file handle
	m_fout.close();
}

/**
 * Register the amount of transfered data on the effected nodes to use later in
 * the clock_tick method.
 */
void LoggerCountBandwidthUtilization::network_transfer(void *sender, void *transfer, unsigned int bytesSent)
{
	m_uploadBandwidths[(Node *)sender] += bytesSent;
	m_downloadBandwidths[(Node *)(((Transfer *)transfer)->m_destination)] += bytesSent;
}

/**
 * Gathers the statistics for each tick
 */
void LoggerCountBandwidthUtilization::clock_tick(unsigned int time)
{
	vector<int> speedsDown;
	vector<int> speedsUp;
	int sumSpeedsDown;
	int sumSpeedsUp;
	int speed;
	Partitionizer *partitionizer = Partitionizer::getInstance();
	std::list<Node *> *nodes = m_eos->getNodes();

	// Write time step
	m_fout << time;

	for (int i=0; i<Partitionizer::getInstance()->getPartitionCount(); i++) {
		speedsDown.clear();
		speedsUp.clear();
		sumSpeedsDown = 0;
		sumSpeedsUp = 0;

		for (std::list<Node *>::iterator node=nodes->begin(); node!=nodes->end(); node++) {
			if(partitionizer->getPartition((*node)) == i){
				// Save downspeed
				speed = (int)((m_downloadBandwidths[(*node)]/(double)(*node)->getBandwidthDown())*100.0);	/// @todo How the heck can this become larger than 100%... Where's the error?
				speedsDown.push_back(speed);
				sumSpeedsDown += speed;

				// Save upspeed
				speed = (int)((m_uploadBandwidths[(*node)]/(double)(*node)->getBandwidthUp())*100.0);	/// @todo How the heck can this become larger than 100%... Where's the error?
				speedsUp.push_back(speed);
				sumSpeedsUp += speed;
			}
		}

		// Write logs for this partition
		writeCountStats(m_fout, speedsDown, sumSpeedsDown);
		writeCountStats(m_fout, speedsUp, sumSpeedsUp);
	}
	m_fout << endl;

	// Reset bandwidths
	resetBandwidths();
}

/**
 * Reset the bandwidths-maps
 */
void LoggerCountBandwidthUtilization::resetBandwidths()
{
	std::list<Node *> *nodes = m_eos->getNodes();
	for (std::list<Node *>::iterator node=nodes->begin(); node!=nodes->end(); node++) {
		m_uploadBandwidths[(*node)] = 0;
		m_downloadBandwidths[(*node)] = 0;
	}
}
